package daobeauty.util;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Utility class for converting method signatures to Strings.
 * 
 * Created 12.09.2008
 * @author M. Serhat Cinar
 * @see Method
 *
 */
public final class MethodSignatureUtils {

	private static final HashMap<Method, String> methodSignaturesByMethod = new HashMap<Method, String>();
	
	private MethodSignatureUtils(){}
	
	@SuppressWarnings("unchecked")
	public static final Map<String, Method> toMethodSignatureMap(Collection clss){
		return toMethodSignatureMap((Class [])clss.toArray(new Class[clss.size()]));
	}
	
	@SuppressWarnings("unchecked")
	public static final Map<String, Method> toMethodSignatureMap(Class [] clss){
		if (clss==null || clss.length<1){
			return Collections.EMPTY_MAP;
		}
		final HashMap<String, Method> signaturesMap = new HashMap<String, Method>();
		for (Class cls:clss){
			signaturesMap.putAll(toMethodSignatureMap(cls));	
		}
		return signaturesMap;
	}
	
	@SuppressWarnings("unchecked")
	public static final Map<String, Method> toMethodSignatureMap(Class cls){
		if (cls==null){
			return Collections.EMPTY_MAP;
		}
		final HashMap<String, Method> signaturesMap = new HashMap<String, Method>();
		signaturesMap.putAll(toMethodSignatureMap(cls.getMethods()));
		signaturesMap.putAll(toMethodSignatureMap(cls.getInterfaces()));
		return signaturesMap;
	}
	
	@SuppressWarnings("unchecked")
	public static final Map<String, Method> toMethodSignatureMap(Method [] methods){
		if (methods==null){
			return Collections.EMPTY_MAP;
		}
		final HashMap<String, Method> signaturesMap = new HashMap<String, Method>();
		for (int i=0; i<methods.length; i++){
			signaturesMap.put(toMethodSignature(methods[i]), methods[i]);
		}
		return signaturesMap;
	}
	
	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Collection clss){
		return toMethodSignature((Class [])clss.toArray(new Class[clss.size()]));
	}
	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Class [] clss, Set<String> methodNameFilters){
		if (clss==null || clss.length<1){
			return Collections.EMPTY_SET;
		}
		final HashSet<String> signatures = new HashSet<String>();
		for (Class cls:clss){
			signatures.addAll(toMethodSignature(cls, methodNameFilters));	
		}
		return signatures;
	}

	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Class [] clss){
		if (clss==null || clss.length<1){
			return Collections.EMPTY_SET;
		}
		final HashSet<String> signatures = new HashSet<String>();
		for (Class cls:clss){
			signatures.addAll(toMethodSignature(cls));	
		}
		return signatures;
	}
	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Class cls, Set<String> methodNameFilters){
		if (cls==null){
			return Collections.EMPTY_SET;
		}
		final HashSet<String> signatures = new HashSet<String>();
		signatures.addAll(toMethodSignature(cls.getMethods(), methodNameFilters));
		signatures.addAll(toMethodSignature(cls.getInterfaces(), methodNameFilters));
		return signatures;
	}

	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Class cls){
		if (cls==null){
			return Collections.EMPTY_SET;
		}
		final HashSet<String> signatures = new HashSet<String>();
		signatures.addAll(toMethodSignature(cls.getMethods()));
		signatures.addAll(toMethodSignature(cls.getInterfaces()));
		return signatures;
	}
	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Method [] methods, Set<String> methodNameFilters){
		if (methods==null){
			return Collections.EMPTY_SET;
		}
		final HashSet<String> signatures = new HashSet<String>();
		for (int i=0; i<methods.length; i++){
			if (!methodNameFilters.contains(methods[i].getName())){
				signatures.add(toMethodSignature(methods[i]));
			}
		}
		return signatures;
	}
	
	@SuppressWarnings("unchecked")
	public static final Set<String> toMethodSignature(Method [] methods){
		if (methods==null){
			return Collections.EMPTY_SET;
		}
		final HashSet<String> signatures = new HashSet<String>();
		for (int i=0; i<methods.length; i++){
			signatures.add(toMethodSignature(methods[i]));
		}
		return signatures;
	}
	
	public static final String toMethodSignature(Method method){
		String signature = methodSignaturesByMethod.get(method);
		if (signature==null){
			final StringBuilder sb = new StringBuilder();
			sb.append(method.getReturnType().getName()+" "+method.getName()+"(");
			final Class [] parameterTypes = method.getParameterTypes();
			if (parameterTypes.length>0){
				for (int i=0; i<parameterTypes.length; i++){
					if (i!=0){
						sb.append(", ");
					}
					sb.append(parameterTypes[i].getName());
				}
			}
			sb.append(")");
			signature = sb.toString();
			methodSignaturesByMethod.put(method, signature);
		}
		return signature;
	}
}
